//
//  Guardian.swift
//  guard
//
//  Created by linus on 2021/11/20.
//

import UIKit

class Guardian: NSObject {
    public typealias call = (Response) -> Void
    
    public static func get(url: String, body: NSDictionary, callback: @escaping Guardian.call) {
        request(url: url, method: "GET", body: body, callback: callback)
    }
    
    public static func post(url: String, body: NSDictionary, callback: @escaping Guardian.call) {
        request(url: url, method: "POST", body: body, callback: callback)
    }
    
    private static func request(url: String, method: String, body: NSDictionary, callback: @escaping Guardian.call) {
        Authing.getPublicConfig { (config) in
            request(config, url, method, body, callback)
        }
    }
    
    public static func request(_ o_config: Config?, _ url: String, _ method: String, _ o_body: NSDictionary?, _ callback: @escaping Guardian.call) {
        guard let u_url = URL(string: url) else {
            print("Guardian: url error")
            return
        }
        
        var req = URLRequest(url: u_url)
        if let config = o_config, let userPoolId = config.userPoolId {
            req.addValue(userPoolId, forHTTPHeaderField: "x-authing-userpool-id")
        }
        
        if method == "POST" {
            req.httpMethod = method
            req.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
            if let body = o_body {
                req.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
            }
        }
        
        URLSession.shared.dataTask(with: req) { (o_data, o_response, o_error) in
            if let error = o_error {
                callback(Response(code: 0, message: error.localizedDescription, obj: nil))
                return
            }
            guard let response = o_response, let url_response = response as? HTTPURLResponse else {
                callback(Response(code: 500, message: "Network Exception", obj: nil))
                return
            }
            guard url_response.statusCode == 200 || url_response.statusCode == 201 else {
                callback(Response(code: url_response.statusCode, message: "Network Error", obj: nil))
                return
            }
            guard let data = o_data else {
                callback(Response(code: 500, message: "Server Error", obj: nil))
                return
            }
            guard let o_result = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) else {
                callback(Response(code: 500, message: "Server Error", obj: nil))
                return
            }
            guard let result = o_result as? NSDictionary else {
                callback(Response(code: 500, message: "Server Error", obj: nil))
                return
            }
            guard let code = result.object(forKey: "code") as? Int else {
                callback(Response(code: 500, message: "Server Error", obj: nil))
                return
            }
            guard let message = result.object(forKey: "message") as? String else {
                callback(Response(code: 500, message: "Server Error", obj: nil))
                return
            }
            guard let config_data = result.object(forKey: "data") as? NSDictionary else {
                callback(Response(code: 500, message: "Server Error", obj: nil))
                return
            }
            callback(Response(code: code, message: message, obj: config_data))
        }.resume()
    }
}
